#include "../lib/control.hpp"

#include <tinyxml.h>
#include <coreutil.hpp>
#include <coreqmanager.hpp>
#include <pipc.hpp>
#include <unistd.h>

static bool checkXML(std::string xml)
{
    TiXmlDocument doc(xml);
    return doc.LoadFile();
}

Controler* Controler::Instance()
{
    static Controler INSTANCE;
    return &INSTANCE;
}

Controler::Controler()
{
    state_ = FILES;
}

Controler::State Controler::getState()
{
    boost::mutex::scoped_lock lock(mutex_);
    return state_;
}

void Controler::loadFiles(std::string chain, std::string route, std::string ipc)
{

    boost::mutex::scoped_lock lock(mutex_);
    if(state_ != FILES)
        return;
    if(!checkXML(chain))
    {
        pland::utill_log(std::string(__FILE__) + " bad chain file " + chain);
        return;
    }
    if(!checkXML(route))
    {
        pland::utill_log(std::string(__FILE__) + " bad route file " + route);
        return;
    }
    chainFile_ = chain;
    routeFile_ = route;

    //Local Settings
    pland::Settings *set = pland::Settings::Instance();
    set->clear();
    set->start();
    pipc::Pipc* Instance = pipc::Pipc::Instance();
    Instance->release();
    if(ipc != "")
    {
        if(checkXML(ipc))
        {
            char buf[100];
            gethostname(buf,100);
            buf[99] ='\n';
            std::string hostname = buf;
            if(Instance->initialize(ipc,hostname))
            {
                pland::utill_log(std::string(__FILE__) + " PIPC started message passing with id: " + hostname);
                Instance->start();
            }
            else
                pland::utill_log(std::string(__FILE__) + " PIPC failed to initialize: " + hostname);
        }
        else
        {
            pland::utill_log(std::string(__FILE__) + " Mallformed PIPC file, not setting up message passing");
        }
    }

    chain_ = new pland::Chain();
    try
    {
        transport_= new kport::Transport(routeFile_);
    }

    catch(pland::Exeption &e)
    {
        pland::utill_log(std::string(__FILE__) + " could not create transport");
        return;
    }
    try
    {
        chain_->create_chain(chainFile_);
    }
    catch(pland::Exeption &e)
    {
        pland::utill_log(std::string(__FILE__) + " could not create chain");
        pland::QueueManager *qman = pland::QueueManager::Instance();
        qman->removeAll();;
        delete transport_;
        return;
    }
    state_ = LISTEN;
}

void Controler::resetState()
{
    pland::QueueManager *qman = pland::QueueManager::Instance();
    qman->stop();
    boost::mutex::scoped_lock lock(mutex_);
    if(state_ == STOP || state_ == RUN)
    {
        transport_->stopListner();
    }
    if(state_ == RUN)
    {
        transport_->stop();
        chain_->stop();

    }
    if(state_ != FILES)
    {
        pland::utill_log(std::string(__FILE__) + " Reseting");
        delete chain_;
        delete transport_;
        pland::QueueManager *qman = pland::QueueManager::Instance();
        qman->removeAll();
    }
    state_ = FILES;
}

void Controler::startListner()
{
    boost::mutex::scoped_lock lock(mutex_);
    if(state_ != LISTEN)
        return;

    std::vector<pland::Chain::Chain_Queue> qs = chain_->queues();
    transport_->loadQueues(qs);
    transport_->startListner();
    pland::QueueManager *qman = pland::QueueManager::Instance();

    qman->start();
    state_ = STOP;
}

void Controler::start()
{
    boost::mutex::scoped_lock lock(mutex_);
    if(state_ == STOP)
        try
    {
        transport_->connectOutbound();
    }
    catch(pland::Exeption &e)
    {
        return;
    }
    if(state_ == STOP || state_ == PAUSE)
    {
        chain_->start();
        transport_->start();
        state_ = RUN;
    }
}

void Controler::pause()
{
    boost::mutex::scoped_lock lock(mutex_);
    if(state_ != RUN)
        return;
    chain_->stop();
    transport_->stop();
    state_ = PAUSE;
}

uint Controler::getAvgLatency()
{
    if(state_ != RUN)
        return 0;
    return transport_->getAvgLatency();
}

uint Controler::getAvgThroughput()
{
    if(state_ != RUN)
        return 0;
    return transport_->getAvgThroughput();
}
